Squeeze Momentum Indicator (TTM Squeeze)

Table of Contents

Squeeze Momentum Indicator (TTM Squeeze)

Overview & Usage Strategy

About the Indicator

The Squeeze Momentum indicator is an adaptation of John Carter’s “TTM Squeeze” volatility indicator, described in chapter 11 of his book “Mastering the Trade.” This technical tool helps traders identify periods of low volatility (the “squeeze”) and potential explosive price movements that often follow. Unlike Carter’s original method, which uses a simple momentum indicator, this version applies a linear regression-based approach to plot the histogram, providing a more nuanced view of momentum dynamics.

Key Takeaways

Formula

The indicator uses two main components:

  1. Volatility Comparison:
    • Bollinger Bands: SMA ± (StdDev × MultFactor)
    • Keltner Channels: SMA ± (ATR × MultFactor)
    • Squeeze occurs when: BBLower > KCLower AND BBUpper < KCUpper
  2. Momentum Calculation:

     Mean = (Highest(high, length)/4 + Lowest(low, length)/4 + SMA(close, length)/2)
     Momentum = LinReg(close - Mean, length, 0)
        
    

How to Interpret Values

Best Practices & Strategy Tips

Code Comparison: Pine Script vs. Indie

Key Differences

Variable Declaration and Access

Series Handling

Default Value Handling

Color Logic

Plotting

Implementation

Indie Implementation Highlights

The core of the Squeeze Momentum indicator’s implementation:

# Detect squeeze conditions
sqz_on = (bb_lower[0] > kc_lower) and (bb_upper[0] < kc_upper)
sqz_off = (bb_lower[0] < kc_lower) and (bb_upper[0] > kc_upper)
no_sqz = (sqz_on == False) and (sqz_off == False)

# Calculate momentum
val = LinReg.new(MutSeriesF.new(self.close[0] - mean(Highest.new(self.high, length_kc),
                                                    Lowest.new(self.low, length_kc),
                                                    Sma.new(self.close, length_kc))),
                  length_kc)

Handling color logic for the histogram:

# Color logic for momentum histogram
bcolor = color.BLACK  # initialization
if val[0] > 0:
    if val[0] > nan_to_zero(val[1]):
        bcolor = color.LIME      # Increasing positive momentum
    else:
        bcolor = color.GREEN     # Decreasing positive momentum
else:
    if val[0] < nan_to_zero(val[1]):
        bcolor = color.RED       # Increasing negative momentum
    else:
        bcolor = color.MAROON    # Decreasing negative momentum

Full Source Code

Indie v5 Code

#Education Purposes
# Ported to Indie from https://www.tradingview.com/script/nqQ1DT5a-Squeeze-Momentum-Indicator-LazyBear/ created by @LazyBear
# More info about the algorithm could be found in the book "Mastering The Trade" by John F Carter

# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.  
# If a copy of the MPL was not distributed with this file, you can obtain one at  
# <https://mozilla.org/MPL/2.0/>.

# indie:lang_version = 5
from math import isnan
from indie import indicator, SeriesF, MutSeriesF, plot, param, color, line_style
from indie.algorithms import Sma, Tr, Bb, Highest, Lowest, LinReg


def mean(s1: SeriesF, s2: SeriesF, s3: SeriesF) -> float:
    return s1[0] / 4 + s2[0] / 4 + s3[0] / 2


def nan_to_zero(val: float) -> float:
    return 0 if isnan(val) else val


@indicator('Squeeze Momentum')
@param.int('length', default=20, min=1, title='BB Length')
@param.float('mult', default=1.5, title='BB MultFactor')
@param.int('length_kc', default=20, min=1, title='KC Length')
@param.float('mult_kc', default=1.5, title='KC MultFactor')
@param.bool('use_true_range', default=True, title='Use TrueRange (KC)')
@plot.histogram(line_width=4, id='#plot_0')
@plot.line(line_style=line_style.SOLID, line_width=4, id='#plot_1')  # TODO: use markers
def Main(self, length, mult, length_kc, mult_kc, use_true_range):
    (bb_lower, _, bb_upper) = Bb.new(self.close, length, mult)

    ma = Sma.new(self.close, length_kc)[0]
    range_s = Tr.new() if use_true_range else MutSeriesF.new(self.high[0] - self.low[0])
    range_ma = Sma.new(range_s, length_kc)[0]
    kc_upper = ma + range_ma * mult_kc
    kc_lower = ma - range_ma * mult_kc

    sqz_on  = (bb_lower[0] > kc_lower) and (bb_upper[0] < kc_upper)
    sqz_off = (bb_lower[0] < kc_lower) and (bb_upper[0] > kc_upper)
    no_sqz  = (sqz_on == False) and (sqz_off == False)

    val = LinReg.new(MutSeriesF.new(self.close[0] - mean(Highest.new(self.high, length_kc),
                                                         Lowest.new(self.low, length_kc),
                                                         Sma.new(self.close, length_kc))),
                     length_kc)

    bcolor = color.BLACK  # just random color to initialize variable
    if val[0] > 0:
        if val[0] > nan_to_zero(val[1]):
            bcolor = color.LIME
        else:
            bcolor = color.GREEN
    else:
        if val[0] < nan_to_zero(val[1]):
            bcolor = color.RED
        else:
            bcolor = color.MAROON

    scolor = color.GRAY
    if no_sqz:
        scolor = color.OLIVE
    elif sqz_on:
        scolor = color.NAVY

    return plot.Histogram(val[0], color=bcolor), plot.Line(0, color=scolor)

Pine Script v5 Code

//Education Purposes
// @author LazyBear 
// List of all my indicators: https://www.tradingview.com/v/4IneGo8h/
//
study(shorttitle = "SQZMOM_LB", title="Squeeze Momentum Indicator [LazyBear]", overlay=false)

length = input(20, title="BB Length")
mult = input(2.0,title="BB MultFactor")
lengthKC=input(20, title="KC Length")
multKC = input(1.5, title="KC MultFactor")

useTrueRange = input(true, title="Use TrueRange (KC)", type=bool)

// Calculate BB
source = close
basis = sma(source, length)
dev = multKC * stdev(source, length)
upperBB = basis + dev
lowerBB = basis - dev

// Calculate KC
ma = sma(source, lengthKC)
range = useTrueRange ? tr : (high - low)
rangema = sma(range, lengthKC)
upperKC = ma + rangema * multKC
lowerKC = ma - rangema * multKC

sqzOn  = (lowerBB > lowerKC) and (upperBB < upperKC)
sqzOff = (lowerBB < lowerKC) and (upperBB > upperKC)
noSqz  = (sqzOn == false) and (sqzOff == false)

val = linreg(source  -  avg(avg(highest(high, lengthKC), lowest(low, lengthKC)),sma(close,lengthKC)), 
            lengthKC,0)

bcolor = iff( val > 0, 
            iff( val > nz(val[1]), lime, green),
            iff( val < nz(val[1]), red, maroon))
scolor = noSqz ? blue : sqzOn ? black : gray 
plot(val, color=bcolor, style=histogram, linewidth=4)
plot(0, color=scolor, style=cross, linewidth=2)

License

MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.